#include "GfxEntityTerrain.h"

CGfxEntityTerrain::CGfxEntityTerrain(int numCellsWide, int numCellsHigh, D3DXVECTOR3 minBound, D3DXVECTOR3 maxBound)
			: m_numCellsWide(numCellsWide), m_numCellsHigh(numCellsHigh), m_minBounds(minBound), m_maxBounds(maxBound),
			m_numVertices(0), m_numTriangles(0), m_vertexBuffer(0), m_indexBuffer(0), m_texture(0), m_numVertsX(0), m_numVertsZ(0)
{
	ZeroMemory(&m_material, sizeof(m_material));
//	m_material.Diffuse.g=1;
//	m_material.Specular.g=1;
	m_material.Diffuse.a=1;
	m_material.Diffuse.r=1;
	m_material.Diffuse.g=1;
	m_material.Diffuse.b=1;
	m_material.Specular.a=1;
	m_material.Specular.r=1;
	m_material.Specular.g=1;
	m_material.Specular.b=1;
}

CGfxEntityTerrain::~CGfxEntityTerrain(void)
{
	m_vertexBuffer->Release();
	m_indexBuffer->Release();
	m_texture->Release();
}

void CGfxEntityTerrain::createTerrain(void)
{
	//calculation of the number of vertices
	m_numVertsX=m_numCellsWide+1;
	m_numVertsZ=m_numCellsHigh+1;
	m_numVertices=m_numVertsX*m_numVertsZ;
	m_numTriangles=m_numCellsWide*m_numCellsHigh*2;
	//calculation of the steps
	float stepX=(m_maxBounds.x-m_minBounds.x)/m_numCellsWide;
	float stepZ=(m_maxBounds.z-m_minBounds.z)/m_numCellsHigh;

	//creation of the vertex buffer
	HRESULT hr=VIS->getDevice()->CreateVertexBuffer(m_numVertices*sizeof(vertexTerrain), D3DUSAGE_WRITEONLY, VERTEXTERRAIN_FVF, D3DPOOL_MANAGED, &m_vertexBuffer, 0);
	if(FAILED(hr))
		exit(1);

	//lock the vertex buffer
	vertexTerrain* pVertices;
	hr=m_vertexBuffer->Lock(0, 0, (void**)&pVertices, 0);
	if(FAILED(hr))
		exit(1);

	//fill in the vertex buffer
	D3DXVECTOR3 position(m_minBounds.x, 0, m_minBounds.z);

	int count=0;

	//loop across z
	for(int i=0; i<m_numVertsZ; i++)
	{
		position.x=m_minBounds.x;

		//loop across x
		for(int j=0; j<m_numVertsX; j++)
		{
			int y=-1+(rand()%2);
			position.y=float(y);
			pVertices[count].m_position=position;
			m_vertexArray.push_back(position);
			pVertices[count].m_normal=D3DXVECTOR3(0, 1, 0);

			pVertices[count].m_textureUCoordinate=((float)j/(m_numVertsX-1));
			pVertices[count].m_textureVCoordinate=(1-(float)i/(m_numVertsZ-1));

			position.x+=stepX;
			count++;
		}

		position.z+=stepZ;
	}

	
	/*pVertices[m_numVertices-m_numVertsX].m_textureUCoordinate=0;
	pVertices[m_numVertices-m_numVertsX].m_textureVCoordinate=0;

	pVertices[m_numVertices].m_textureUCoordinate=5;
	pVertices[m_numVertices].m_textureVCoordinate=0;

	pVertices[0].m_textureUCoordinate=0;
	pVertices[0].m_textureVCoordinate=5;

	pVertices[m_numVertsX-1].m_textureUCoordinate=5;
	pVertices[m_numVertsX-1].m_textureVCoordinate=5;*/

	
	//calculation of the normals
	for(count=0; count<m_numVertices; count++)
	{
		if(count==0)
		{
			D3DXVECTOR3 v1=pVertices[count+m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count+m_numVertsX+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v4=pVertices[count+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVECTOR3 cross2;
			D3DXVec3Cross(&cross1, &v1, &v2);
			D3DXVec3Cross(&cross2, &v2, &v4);
			pVertices[count].m_normal=(cross1+cross2);
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		else if(count==m_numCellsWide)
		{
			D3DXVECTOR3 v1=pVertices[count-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count+m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVec3Cross(&cross1, &v1, &v2);
			pVertices[count].m_normal=cross1;
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		else if(count==m_numVertices-1)
		{
			D3DXVECTOR3 v1=pVertices[count-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v3=pVertices[count-m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count-m_numVertsX-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVec3Cross(&cross1, &v1, &v2);
			D3DXVECTOR3 cross2;
			D3DXVec3Cross(&cross2, &v2, &v3);
			pVertices[count].m_normal=cross1+cross2;
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		else if(count==m_numVertices-m_numCellsWide)
		{
			D3DXVECTOR3 v1=pVertices[count+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count-m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVec3Cross(&cross1, &v1, &v2);
			pVertices[count].m_normal=cross1;
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		else if(count>0 && count<m_numVertsX-1)
		{
			D3DXVECTOR3 v1=pVertices[count-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count+m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v3=pVertices[count+m_numVertsX+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v4=pVertices[count+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVec3Cross(&cross1, &v1, &v2);
			D3DXVECTOR3 cross2;
			D3DXVec3Cross(&cross2, &v2, &v3);
			D3DXVECTOR3 cross3;
			D3DXVec3Cross(&cross3, &v3, &v4);
			pVertices[count].m_normal=cross1+cross2+cross3;
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		else if(count>m_numVertices-m_numCellsWide && count<m_numVertices)
		{
			D3DXVECTOR3 v1=pVertices[count-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count-m_numVertsX+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v3=pVertices[count-m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v4=pVertices[count+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVec3Cross(&cross1, &v1, &v2);
			D3DXVECTOR3 cross2;
			D3DXVec3Cross(&cross2, &v2, &v3);
			D3DXVECTOR3 cross3;
			D3DXVec3Cross(&cross3, &v3, &v4);
			pVertices[count].m_normal=cross1+cross2+cross3;
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		else if(count%m_numVertsX==0)
		{
			D3DXVECTOR3 v1=pVertices[count-m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v3=pVertices[count+m_numVertsX+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v4=pVertices[count+m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVec3Cross(&cross1, &v1, &v2);
			D3DXVECTOR3 cross2;
			D3DXVec3Cross(&cross2, &v2, &v3);
			D3DXVECTOR3 cross3;
			D3DXVec3Cross(&cross3, &v3, &v4);
			pVertices[count].m_normal=cross1+cross2+cross3;
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		else if(count%m_numVertsX==m_numVertsX-1)
		{
			D3DXVECTOR3 v1=pVertices[count-m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count-m_numVertsX-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v3=pVertices[count-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v4=pVertices[count+m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVec3Cross(&cross1, &v1, &v2);
			D3DXVECTOR3 cross2;
			D3DXVec3Cross(&cross2, &v2, &v3);
			D3DXVECTOR3 cross3;
			D3DXVec3Cross(&cross3, &v3, &v4);
			pVertices[count].m_normal=cross1+cross2+cross3;
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		else
		{
			D3DXVECTOR3 v1=pVertices[count-m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v2=pVertices[count+1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v3=pVertices[count+1+m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v4=pVertices[count+m_numVertsX].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v5=pVertices[count-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 v6=pVertices[count-m_numVertsX-1].m_position-pVertices[count].m_position;
			D3DXVECTOR3 cross1;
			D3DXVec3Cross(&cross1, &v1, &v2);
			D3DXVECTOR3 cross2;
			D3DXVec3Cross(&cross2, &v2, &v3);
			D3DXVECTOR3 cross3;
			D3DXVec3Cross(&cross3, &v3, &v4);
			D3DXVECTOR3 cross4;
			D3DXVec3Cross(&cross4, &v4, &v5);
			D3DXVECTOR3 cross5;
			D3DXVec3Cross(&cross5, &v5, &v6);
			D3DXVECTOR3 cross6;
			D3DXVec3Cross(&cross6, &v6, &v1);
			pVertices[count].m_normal=cross1+cross2+cross3+cross4+cross5+cross6;
			D3DXVec3Normalize(&pVertices[count].m_normal, &pVertices[count].m_normal);
		}
		if(pVertices[count].m_normal.y<0)
				pVertices[count].m_normal.y*=-1;

	}

	//load the texture
	hr=D3DXCreateTextureFromFile(VIS->getDevice(),".\\data\\Textures\\mud.jpg", &m_texture);
	if(FAILED(hr))
		exit(1);


	//unlock the vertex buffer
	m_vertexBuffer->Unlock();

	//creation of the index buffer
	hr=VIS->getDevice()->CreateIndexBuffer(2*m_numTriangles*3, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_indexBuffer, 0);
	if(FAILED(hr))
		exit(1);

	//lock the index buffer
	WORD* indices=0;
	m_indexBuffer->Lock(0, 0, (void**)&indices, 0);

	//fill in the index buffer
	count=0;
	int index=0;
	//loop through z
	for(int i=0; i<m_numCellsHigh; i++)
	{
		//loop through x
		for(int j=0; j<m_numCellsWide; j++)
		{
			//first triangle
			indices[count++]=(WORD)index;
			indices[count++]=(WORD)(index+m_numVertsX);
			indices[count++]=(WORD)(index+m_numVertsX+1);
		
			//second triangle
			indices[count++]=(WORD)index;
			indices[count++]=(WORD)(index+m_numVertsX+1);
			indices[count++]=(WORD)(index+1);

			index++;
		}
		index++;
	}

	//unlock the indices buffer
	m_indexBuffer->Unlock();

	

	

}

void CGfxEntityTerrain::doRender()
{
	VIS->getDevice()->SetMaterial(&m_material);
	//VIS->getDevice()->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	VIS->getDevice()->SetTexture(0, m_texture);
	VIS->getDevice()->SetStreamSource(0, m_vertexBuffer, 0, sizeof(vertexTerrain));
	VIS->getDevice()->SetFVF(VERTEXTERRAIN_FVF);
	VIS->getDevice()->SetIndices(m_indexBuffer);

	HRESULT hr=VIS->getDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_numVertices, 0, m_numTriangles);
	if(FAILED(hr))
		exit(1);
}

D3DXVECTOR3 CGfxEntityTerrain::getMinBound()const
{
	return m_minBounds;
}

D3DXVECTOR3 CGfxEntityTerrain::getMaxBound()const
{
	return m_maxBounds;
}

int CGfxEntityTerrain::getNumCellWidth()const
{
	return m_numCellsWide;
}

int CGfxEntityTerrain::getNumCellHigh()const
{
	return m_numCellsHigh;
}

D3DXVECTOR3 CGfxEntityTerrain::getVertex(int indexVertex)const
{
	return m_vertexArray[indexVertex];
}